<template>
  <div :style="{width:`${browserW+50}px`,height:`${browserH+50}px`}" style="overflow: hidden;">
    <div>
      <vue-ruler-tool
        :parent="true"
        :step-length="fixedScaleRatio"
        :style="{width:`${browserW+50}px`,height:`${browserH+50}px`}"
        class="ruler"
        v-model="presetLine">

        <!--   画布限制区域   -->
        <div :style="browserShowStyle">
          <!--          <div :style="wrapperClothStyle"
                         class="full-moon-cloth-wrap"> -->
          <!--                   :class="[{'selected':isSelectClass(grid)}]"
               -->

          <!--     真实画布,需要缩放
                   :is-conflict-check="true"
  -->
          <div  :style="paintClothStyle" @contextmenu.prevent ref="paintCloth">
            <vue-draggable-resizable
              :h="grid.h"
              :uid="grid.key"
              :key="`grid${grid.key}`"
              :parent="true"
              :resizable="false"
              :scale-ratio="minScaleRadio"
              :snap="true"
              :snap-tolerance="adsorption"
              :style="borderStyleFn(grid)"
              :w="grid.w"
              :x="grid.x"
              :y="grid.y"
              @deactivated="onDeactivated(grid,idx)"
              @activated="onActivated(grid,idx)"
              @contextmenu.native.stop.prevent=" $event => handleGridContextmenu({$event,grid,idx,gridList})"
              @dragstop="(left,top)=>dragstop({left,top,grid,idx})"
              @refLineParams="getRefLineParams"
              v-for="(grid,idx) in gridList">
              <slot :data="{grid, idx,gridList}"></slot>
              <!--           @resizestop="(left,top,width,height)=>resizestop({left,top,width,height,grid,idx})"     -->
              <!--        <div @click="removeItem(grid,idx)">delete</div>-->
            </vue-draggable-resizable>

            <!--辅助线-->
            <!--      <transition-group name="list">-->
            <span :key="`v${item.id}`"
                  :style="{ left: item.position, top: item.origin, height: item.lineLength,width:`${borderWH}px`}"
                  class="ref-line v-line list-item"
                  v-for="item in vLine"
                  v-show="item.display"
            />
            <span :key="`h${item.id}`"
                  :style="{ top: item.position, left: item.origin, width: item.lineLength,height:`${borderWH}px`}"
                  class="ref-line h-line list-item"
                  v-for="item in hLine"
                  v-show="item.display"
            />

            <!--      </transition-group>-->
            <!--辅助线END-->
          </div>
          <!--          </div>-->
        </div>
      </vue-ruler-tool>
    </div>
    <v-contextmenu ref="contextmenu">
      <slot :contextMenuStore="contextMenuStore" name="contextMenu">
        <v-contextmenu-item>名称 : grid {{contextMenuStore.grid.key}} ⚛</v-contextmenu-item>
        <v-contextmenu-item divider></v-contextmenu-item>
        <!--        <v-contextmenu-item>move to left</v-contextmenu-item>-->
        <!--        <v-contextmenu-item>move to top</v-contextmenu-item>-->
        <v-contextmenu-group :max-width="240">
          <v-contextmenu-item>
            {{`x : ${contextMenuStore.grid.x}`}}
          </v-contextmenu-item>
          <v-contextmenu-item>
            {{`y : ${contextMenuStore.grid.y}`}}
          </v-contextmenu-item>
        </v-contextmenu-group>

        <v-contextmenu-group :max-width="240">
          <v-contextmenu-item>
            {{`w : ${contextMenuStore.grid.w}`}}
          </v-contextmenu-item>
          <v-contextmenu-item>
            {{`h : ${contextMenuStore.grid.h}`}}
          </v-contextmenu-item>
        </v-contextmenu-group>

        <v-contextmenu-item divider></v-contextmenu-item>

        <v-contextmenu-item>
          {{`角度 : ${contextMenuStore.grid.rotateAngle}°`}}
        </v-contextmenu-item>
      </slot>
      <slot :contextMenuStore="contextMenuStore" name="otherContextMenu"></slot>
    </v-contextmenu>
  </div>
</template>

<script>
  import VueDraggableResizable from './components/vue-draggable-resizable'
  import './components/vue-draggable-resizable.css'
  import {
    ref,
    reactive,
    toRefs,
    unref,
    watch,
    computed,
    watchEffect,
    set,
    nextTick,
    onMounted
  } from '@vue/composition-api'
  import { debugLogger } from '@/utils/fridayClub/functianal'
  import { isObject } from '@/utils/commons'
  import VueRulerTool from 'vue-ruler-tool'

  const noop = () => {
  }

  /**
   * 转换比例
   * @deprecated
   */
  const calcRatioFn = (radio) => ({ x, y, w, h }) => {
    return { x: x * radio, y: y * radio, w: w * radio, h: h * radio }
  }

  /**
   * 转换比例
   * @deprecated
   */
  const transferRatio = (gridList) => {
    const _transferRatio = (grid) => {
      Object.assign(grid, calcRatioFn(0.5)(grid))
    }
    if (Array.isArray(gridList)) {
      (gridList.forEach(_transferRatio))
    } else {
      _transferRatio(gridList)
    }
    return gridList
  }

  /**
   *  添加额外的属性
   * @param gridList Array | Object
   */
  const addProps = (gridList) => {
    const add = grid => {
      // Object.assign(unref(grid), {
      //   bc: getRandomColor(),
      // })
      // set(unref(grid), 'bc', getRandomColor())
    }
    if (Array.isArray(gridList)) {
      (gridList.forEach(add))
    } else {
      add(gridList)
    }
    return gridList
  }

  function useClothHook({ props } = {}) {
    const browserShowStyle = computed({
      get() {
        return {
          width: `${props.browserW}px`,
          height: `${props.browserH}px`
        }
      }
    })

    const clothRatioW = computed({
      get() {
        return props.browserW / props.paintCloth.w
      }
    })

    const clothRatioH = computed({
      get() {
        return props.browserH / props.paintCloth.h
      }
    })

    const wThanH = computed({
      get() {
        return unref(clothRatioW) > unref(clothRatioH)
      }
    })

    // console.log(`%c the val => ${clothRatioW.value} `, 'color:#fff;border:1px solid deepskyblue;background:deepskyblue;border-radius: 5px;padding:0 5px')
    // console.log(`%c the val => ${clothRatioH.value} `, 'color:#fff;border:1px solid deepskyblue;background:deepskyblue;border-radius: 5px;padding:0 5px')

    const minScaleRadio = computed(() => Math.min(clothRatioW.value, clothRatioH.value))
    const paintClothStyle = computed({
      get() {
        const { bc = 'deepskyblue', bs = 1, w, h } = props.paintCloth
        const b =
          ['top', 'left', 'right', 'bottom'].reduceRight((acc, c) => {
            return Object.assign({}, acc, { [`border-${c}`]: `${bs}px solid ${bc}` })
          }, {})

        console.log(b)

        return {
          width: `${w}px`,
          height: `${h}px`,
          boxSizing: 'content-box',
          transform: `scale(${minScaleRadio |> unref})`, //  ,${clothRatioH.value}
          transformOrigin: 'left top',
          ...b,
          ...props.cusPaintClothStyle

        }
      }
    })

    const wrapperClothStyle = computed({
      get() {
        return {
          width: `${props.browserW}px`,
          height: `${props.browserH}px`
        }
      }
    })

    return { wrapperClothStyle, paintClothStyle, clothRatioW, minScaleRadio, browserShowStyle, wThanH }
  }

  function useAuxiliaryLineHook() {
    const auxiliaryLines = reactive({
      vLine: [],
      hLine: [],
      presetLine: []
    })

    //   :debug="false"
    const getRefLineParams = (params) => {
      const { vLine, hLine } = params
      // console.log(vLine)
      // console.log(hLine)
      let id = 0

      auxiliaryLines.vLine = vLine.map(item => {
        item['id'] = ++id
        return item
      })
      auxiliaryLines.hLine = hLine.map(item => {
        item['id'] = ++id
        return item
      })
    }
    return { getRefLineParams, auxiliaryLines }
  }

  function useOperatorHook({ gridList: gridListRef } = {}) {
    const gridList = unref(gridListRef)

    const addRect = ({ x, y, w, h }) => {
      gridList.push({ x, y, w, h } |> addProps)
    }

    const removeRect = ({ idx, key }) => {
      const findFn = v => v.key === key
      if (key) {
        gridList.splice(idx, gridList.findIndex(findFn))
      } else if (idx) {
        gridList.splice(idx, 1)
      }
    }

    const editRect = (rectItem) => {
      const { key, w, h, x, y } = rectItem
      if (!key) {
        return console.log('编辑的rect 必须有 独一无二的 key')
      }

      const findFn = v => v.key === key

      gridList.splice(gridList.findIndex(findFn),
        1,
        Object.assign(gridList.find(findFn), { w, h, x, y }))
    }

    return { addRect, removeRect, editRect }
  }

  function useGridListHook({ dataList, ctx, userConfig } = {}) {

    const gridList = dataList |> addProps |> ref

    //  直接更新了指针,把父类的的dataList 整个刷新了
    watch(gridList, dataList => {
      ctx.emit('update:dataList', dataList)
    }, { deep: true })

    const dragstop = ({ left, top, grid, idx } = {}) => {
      Object.assign(unref(gridList)[idx], { x: left, y: top })
    }

    const resizestop = ({ left, top, width, height, grid, idx } = {}) => {
      Object.assign(grid, { x: left, y: top, w: width, h: height })
    }

    const adsorption = computed(() => {

      // let v = 10
      // if (unref(gridList).length === 0) {
      //   v = 10
      // } else if (unref(gridList).length === 1) {
      //   const { [0]: { w, h } } = unref(gridList)
      //   v = Math.min(w, h)
      // } else {
      //   v = unref(gridList).reduce((pre, { w, h }) => {
      //     console.log('reduce ~~~~~')
      //     console.log(pre)
      //     console.log({ w, h })
      //
      //     if (isObject(pre)) {
      //       return Math.min(w, h, pre.w, pre.h)
      //     }
      //     return Math.min(w, h, pre)
      //   })
      // }
      // // console.log(`%c the val => ${v} `, 'color:#fff;border:1px solid deepskyblue;background:deepskyblue;border-radius: 5px;padding:0 5px')
      // return v * 0.1 |> Math.ceil

      return userConfig.snapSpace
    })

    return { resizestop, dragstop, gridList, adsorption }
  }

  function useContextMenuHook({ contextmenuName = 'contextmenu' } = {}) {
    const contextMenuStore = reactive({ grid: {}, idx: -1 })

    function handleGridContextmenu(v) {
      console.log(v)
      const { $event, ...rest } = v//  grid, idx, gridList
      // console.log($event)
      // console.log(rest)
      // $event.stopPropagation()
      // $event.preventDefault();
      // ({ grid: contextMenuStore.grid, idx: contextMenuStore.idx } = rest)
      // console.log(contextMenuStore)
      // console.log(contextMenuStore.grid)
      // console.log(contextMenuStore.idx)
      contextMenuStore.grid = rest.grid
      contextMenuStore.idx = rest.idx
      this.$refs[contextmenuName].show({
        top: $event.clientY,
        left: $event.clientX
      })
    }

    return { handleGridContextmenu, contextMenuStore }
  }

  function useRulerHook({ minScaleRadio, props, wThanH } = {}) {
    const fixedScaleRatio = computed(() => {
      // const fixedRadio = this.scaleRatio.toFixed(1) |> parseFloat
      // console.log(`${this.scaleRatio} fixedRadio`)
      // console.log((this.scaleRatio |> Math.ceil) * 50)

      // props.browserW / props.paintCloth.w

      // console.log(
      //   `%c azure full moon  %c Detected Vue v${`~~~~~`} %c`,
      //   'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px;  color: #fff',
      //   'background:#41b883 ; padding: 1px; border-radius: 0 3px 3px 0;  color: #fff',
      //   'background:transparent'
      // )
      // console.log(props.paintCloth.h);
      // console.log(props.browserH);
      // console.log(unref(minScaleRadio));

      // return (minScaleRadio.value |> Math.ceil) * 50
      const { h: ph, w: pw } = props.paintCloth
      if (!ph || !pw) {
        return 50
      }

      //  //  12
      console.log('~~~~~~~~~')

      const toRoundOne = v => Math.round(v * 10) / 10  // Math.round(number * 100) / 100);

      const stepH = ph / 8 |> Math.round
      const stepW = pw / 12  |> Math.round
      console.log(stepH)
      console.log(stepW)
      console.log(unref(wThanH))
      return unref(wThanH) ? stepH : stepW
      //  |> Math.ceil
      // return (minScaleRadio.value |> Math.ceil) * 50
    })

    return { fixedScaleRatio }
  }

  export default {
    name: 'FullMoon',
    props: {
      dataList: {
        default: () => ([]),
        type: Array
      },
      paintCloth: {
        default: () => ({ w: 6000, h: 4000 }),
        type: Object
      },
      browserW: {
        type: Number,
        default: 600
      },
      browserH: {
        type: Number,
        default: 400
      },
      activeKey: {
        type: Number,
        default: -100
      },
      cusPaintClothStyle: {
        type: Object
      },
      userConfig: {
        type: Object
      },
      gridStyleFn:{
        type:Function
      }
    }, components: { VueDraggableResizable, VueRulerTool },
    setup(props, ctx) {
      console.log(ctx)
      const { wrapperClothStyle, paintClothStyle, minScaleRadio, browserShowStyle, wThanH } = useClothHook({ props })
      const { getRefLineParams, auxiliaryLines } = useAuxiliaryLineHook()
      const { gridList, adsorption, ...dragEvt } = useGridListHook({
        dataList: props.dataList,
        ctx,
        userConfig: props.userConfig
      })
      const operators = useOperatorHook({ gridList })
      const { handleGridContextmenu, contextMenuStore } = useContextMenuHook()

      const { fixedScaleRatio } = useRulerHook({ minScaleRadio, props, wThanH })

      // onMounted(async() => {
      //   await nextTick()
      //   console.log(ctx, props)
      //   const el = ctx.refs['paintCloth']
      //   console.log('el =>>>>> %o', el)
      //   el.addEventListener('mousedown', (e) => {
      //     if (e.button === 0) { // 鼠标左键
      //       if (e.ctrlKey) { //  ctrl
      //         console.log('mousedown %o', e)
      //         console.log('ctrlKey')
      //
      //       }
      //     }
      //   })
      // })

      const activeGridData = reactive({
        curSelectGrid: {},
        curSelectGridIdx: -1
      })

      const onActivated = (grid, idx) => {
        // console.log(grid, idx)
        activeGridData.curSelectGrid = grid
        activeGridData.curSelectGridIdx = idx
        ctx.emit('update:activeKey', grid.key)
        ctx.emit('activeGrid', { grid, idx })
      }

      const onDeactivated = (grid, idx) => {
        ctx.emit('deactivated', { grid, idx })
      }

      const isSelectClass = (grid) => {
        return grid.key === props.activeKey
      }

      const borderStyleFn = computed(() => {
        const { w, h } = props.paintCloth
        //  isSelectClass
        return (grid) => {
          const base = {
            // transition: 'border .3s',
            background: grid.bc
          }
          if (isSelectClass(grid)) {
            Object.assign(base, { border: `${Math.min(w, h) / 200 |> Math.ceil}px dashed #000000` })
          }
          if (props.gridStyleFn) {
            Object.assign(base, props.gridStyleFn(grid))
          }
          return base
        }
      })

      const { w, h } = props.paintCloth

      console.log(w, h)
      console.log(Math.min(w, h))

      const borderWH = Math.min(w, h) / 175 |> Math.ceil

      console.log(borderWH)

      return {
        ...toRefs(auxiliaryLines), getRefLineParams, gridList,
        paintClothStyle, ...operators, ...dragEvt, wrapperClothStyle, minScaleRadio, adsorption
        , handleGridContextmenu, contextMenuStore, browserShowStyle, fixedScaleRatio, onActivated
        , isSelectClass, borderStyleFn, borderWH,onDeactivated
      }
    }

  }
</script>

<style lang="scss" scoped>

  /*.list-item {*/
  /*  display: inline-block;*/
  /*}*/

  /*.list-enter-active, .list-leave-active {*/
  /*  transition: all .8s;*/
  /*}*/

  /*.list-enter, .list-leave-to {*/
  /*  opacity: 0;*/
  /*}*/

  /*.selected {*/
  /*  border: 20px dashed #1f6fc9;*/
  /*}*/


</style>
